#include "rx203_ptcl_parsor.h"


#include <QFile>




/********************************* ParseTask ********************************/

ParseWorker::ParseWorker(QImage *image, QVector<QVector<PortPar *> *> *p_par_vec,
                         QObject *parent) :
    QObject(parent),
    flag_run(true),
    image(image),
    p_par_vec(p_par_vec)
{

}

ParseWorker::~ParseWorker()
{

}

int ParseWorker::parse(QByteArray* display_pkt_data)
{
//    if (display_pkt_data == NULL) {
//        qErrnoWarning("raw_data pointor is NULL! ");
//        return -1;

//    }



    Pkt_Display* p_pkt = (Pkt_Display*)display_pkt_data->data();

    int sub_dev_id = (int)p_pkt->ctrl_num;
    int port_id = p_pkt->bit_port_no;

    //顾及效率 就不检查了

    //qDebug("sub_dev_id: %d, port_id:%d", sub_dev_id, port_id);
    //qDebug("sub_dev_num: %d, port_num:%d", p_par_vec->size(),
//           (*p_par_vec)[sub_dev_id - 1]->size());
    PortPar* port_par = (*(*p_par_vec)[sub_dev_id - 1])[port_id - 1];

    if (port_par == NULL || (uint8_t)port_par->addr->at(0) == ((uint8_t)0xff)) {
        //占位包跳过
        return 0;
    }

    int img_size = image->size().width() * image->size().height();
    //qDebug("img size: %d", img_size);
    for (int i = 0; i < 255; i++) {
        uint8_t* p = (uint8_t*)&port_par->addr->data()[i * 3];
        //qDebug("addr : %ld", (char*)p - port_par->addr->data());
        //qDebug("p[0]: %02hhx, p[1]:%02hhx, p[2]: %02hhx", p[0], p[1], p[2]);
        int offset = (p[0] << 16) + (p[1] << 8) + (p[2]) - 1;
        //qDebug("img size: %d, offset:%d", img_size, offset);

        if (offset <= img_size - 2) {
            *(image->bits() + (3 * offset)) = p_pkt->rgb_data[i * 3];
            *(image->bits() + (3 * offset + 1)) = p_pkt->rgb_data[i * 3 + 1];
            *(image->bits() + (3 * offset + 2)) = p_pkt->rgb_data[i * 3 + 2];
        } else {
            qErrnoWarning("offset(%d) is out of range(%d)",
                          offset, img_size);
        }
    }

    return 0;
}


void ParseWorker::parseThread()
{
    qDebug("[%s] entry thread tid(%lu)", __func__, QThread::currentThreadId());

    while (flag_run) {
        current_task->mutex.lock();
        //current_task->idle_wokers_number++;
        current_task->idle_workers_number++;

        //如果发现队列为空，线程全部空闲，且收到了同步帧
        if (current_task->input_pkt_display_list->empty()) {
            if (current_task->idle_workers_number ==
                    current_task->wokers_number) {
                current_task->mutex.unlock();
                //最后一个线程把 任务 释放
                delete current_task;
                emit signal_frameComplete();
            } else {
                current_task->mutex.unlock();
            }
            break;
        }
        //队列非空 取一包数据
        QByteArray* raw_data = *current_task->input_pkt_display_list->begin();
        current_task->input_pkt_display_list->pop_front();
        //current_task->idle_wokers_number--;
        current_task->idle_workers_number--;
        current_task->mutex.unlock();

        //解析
        parse(raw_data);
        delete raw_data;
    }
    qDebug("[%s] exit thread tid(%lu)", __func__, QThread::currentThreadId());

}









/***************************** RX203_PTCL_Parsor *****************************/
RX203_PTCL_Parsor::RX203_PTCL_Parsor(QString par_file_path,
                                     int worker_num, QObject *p) :
    ParsorBase(p),
    par_file_path(par_file_path),
    udp_recv_frame(NULL),
    task_busy(false),
    workers_num(worker_num)
{
    Q_ASSERT(RX203_DISPLAY_PKT_LEN == sizeof(Pkt_Display));

    //设置造型
    if (setParFile() != 0) {
        throw RX203_ERR_CODE_PAR_FILE_ERR;
    }


    //创建任务队列
    taskListInit();

    //创建解析线程组
    threadSetInit();

    portFlagInit();

}

RX203_PTCL_Parsor::~RX203_PTCL_Parsor()
{
    //停止线程
    threadSetDeinit();
    //清空任务队列
    taskListDeinit();
    //清空造型
    clearParFile();
}

void RX203_PTCL_Parsor::addRawPkt(QByteArray& raw_data)
{
    if (raw_data.size() != RX203_DISPLAY_PKT_LEN) {
        qErrnoWarning("[%s] recv size err:%d", __func__, raw_data.size());
        return;
    }

    if (udp_recv_frame == NULL) {
        udp_recv_frame = new FrameOfPkt();
        udp_recv_frame->wokers_number = workerNodes_vec.size();
        udp_recv_frame->input_pkt_display_list = new QList<QByteArray*>();
    }

    bool discard = false;

    //检查是否为同步帧
    if (0x0f == (uint8_t)raw_data.at(0) && 0xff == (uint8_t)raw_data.at(2)) {
        portFlagclear();
        task_list_mutex.lock();
        if (task_list.length() > 2) {
            discard = true;
        } else {
            qDebug("get here!");
            task_list.push_back(udp_recv_frame);
            udp_recv_frame = NULL;
            if (!task_busy) {
                qDebug("task comoing ! get up to work!");

                FrameOfPkt* new_task = *task_list.begin();
                task_list.pop_front();
                task_busy = true;
                foreach (WorkerNode* wk, workerNodes_vec) {
                    wk->worker->setCurrentTask(new_task);
                    wk->thread->exit();
                    wk->thread->wait();
                    emit wk->thread->start();
                }
            }
        }
        task_list_mutex.unlock();

    } else {

        Pkt_Display* p_pkt = (Pkt_Display*)raw_data.data();
        if (p_pkt->cmd != RX203_DISPLAY_CMD) {
            qErrnoWarning("get raw_data_len cmd (%hhu) is not equal (%hhu)",
                          p_pkt->cmd, RX203_DISPLAY_CMD);
            discard = true;
        } else {
            QByteArray* data = new QByteArray(raw_data);
            Pkt_Display* p_pkt = (Pkt_Display*)data->data();
            int sub_dev_id = (int)p_pkt->ctrl_num;
            int port_id = getPortId(p_pkt->bit_port_no);
            port_flag_vec_mutex.lock();
            if (port_flag_vec[sub_dev_id - 1]->port_x_get[port_id] == true) {
                p_pkt->bit_port_no = port_id + 4;
            } else {
                p_pkt->bit_port_no = port_id;
                port_flag_vec[sub_dev_id - 1]->port_x_get[port_id] = true;
            }
            port_flag_vec_mutex.unlock();
            //qDebug("raw data : sub_id :%d, port id : %d", sub_dev_id, port_id);
            udp_recv_frame->input_pkt_display_list->push_back(data);

        }
    }

    if (discard) {
        foreach (QByteArray* t, *(udp_recv_frame->input_pkt_display_list)) {
            delete t;
        }
        delete udp_recv_frame->input_pkt_display_list;
        delete udp_recv_frame;
        udp_recv_frame = NULL;
        return;
    }

}



void RX203_PTCL_Parsor::slot_getFrameCompelet()
{
    qDebug("[%s] get a frame", __func__);
    //通知上层显示
    emit signal_frameready();

    //解完了一帧，需要给每个 线程切换工作队列
    task_list_mutex.lock();
    if (task_list.empty()) {
        task_busy = false;
    } else {
        task_busy = true;
        FrameOfPkt* new_task = *task_list.begin();
        task_list.pop_front();
        foreach (WorkerNode* wk, workerNodes_vec) {
            wk->worker->setCurrentTask(new_task);
            wk->thread->exit();
            wk->thread->wait();
            wk->thread->start();
        }
    }
    task_list_mutex.unlock();

    //关闭线程


}

inline int RX203_PTCL_Parsor::getPortId(uint8_t v)
{
    switch (v) {
    case 1:
        return 1;
    case 2:
        return 2;
    case 4:
        return 3;
    case 8:
        return 4;
    default:
        return -1;
    }
    return -1;
}

#include <stdio.h>
int RX203_PTCL_Parsor::setParFile()
{
    int ret = -1;

    QByteArray head;
    Pkt_ParHead* pkt_parhead = NULL;
    int port_num;
    int sub_dev_num;
    QByteArray& tmp = head;

    QVector<QVector<PortPar*>*>:: Iterator it;

    QFile file(par_file_path);
    if (!file.open(QIODevice::ReadOnly)) {
        qErrnoWarning("file path [%s] not exist!",
                      par_file_path.toStdString().c_str());
        ret = -1;
        goto EXIT;
    }

    if (file.size() % RX203_DISPLAY_PKT_LEN != 0) {
        qErrnoWarning("file [%s] not in rule! file size:%d", file.size());
        ret = -1;
        goto EXIT;
    }

    head = file.read(RX203_DISPLAY_PKT_LEN);

    pkt_parhead = (Pkt_ParHead*)head.data();

    int w, h;
    w = (int)htobe16(pkt_parhead->w);
    h = (int)htobe16(pkt_parhead->h);

    image = new QImage(w, h, QImage::Format_RGB888);

    //端口个数
    port_num = (int)htobe16(pkt_parhead->port_num);
    if (file.size() != (RX203_DISPLAY_PKT_LEN * (port_num + 1))) {
        qErrnoWarning("file size:%d not in rule! port_num:%d",
                      file.size(), port_num);
        ret = -1;
        goto EXIT;
    }
    qDebug("get port number %d", port_num);

    //计算分控个数
    tmp.clear();
    file.seek(file.size() - 779);
    tmp = file.read(RX203_DISPLAY_PKT_LEN);
    sub_dev_num = (int)((Pkt_Display*)tmp.data())->ctrl_num;
    qDebug("get sub dev number %d", sub_dev_num);
    par_vec.resize(sub_dev_num);
    it = par_vec.begin();
    for (; it != par_vec.end(); it ++) {
        (*it) = new QVector<PortPar*>(RX203_PORT_NUM);
        for (int i = 0; i < (*it)->size(); i++) {
            (**it)[i] = NULL;
        }
//        QVector<PortPar*>::Iterator i = (*it)->begin();
//        for (; i != (*it)->end(); i++) {
//            (*i) = NULL;
//        }
    }

    file.seek(779);
    while (!file.atEnd()) {
        tmp.clear();
        tmp = file.read(RX203_DISPLAY_PKT_LEN);

        //debug
//        int len = tmp.size();
//        qDebug("length : %d", len);
//        int i = 0;
//        for (; i < len; i++) {
//            printf("%02hhx ", tmp.at(i));
//            if ((i + 1) % 16 == 0) {
//                printf("\n");
//            }
//        }
//        printf("----------------------------------------\n\n");


        Pkt_Display* pkt_display = (Pkt_Display*)tmp.data();
        int sub_dev_id = (int)pkt_display->ctrl_num;
        if (sub_dev_id > sub_dev_num) {
            qErrnoWarning("sub_dev_num:%d, pkt_display->ctrl_num:%hhu",
                          sub_dev_num, pkt_display->ctrl_num);
            ret = -1;
            goto EXIT;
        }
        //int packet_no; 用不上
        //qDebug("pkt_display->bit_port_no: %hhx", *(uint8_t*)&pkt_display->ctrl_num);
        int port_id = getPortId(pkt_display->bit_port_no);
        if (port_id == -1) {
            qErrnoWarning("file not in rule! port_id:%hhu",
                          pkt_display->bit_port_no);
            ret = -1;
            goto EXIT;
        }

        int rgb_data_offset = GET_OFFSET(Pkt_Display, rgb_data);
        //判断是否是没有有效点的端口造型(第一个和第五个端口的占位数据)
        //取第一个点的地址看看是否有效
//        if ((uint8_t)tmp.at(rgb_data_offset) == (uint8_t)0xff &&
//                (uint8_t)tmp.at(rgb_data_offset + 1) == (uint8_t)0xff &&
//                (uint8_t)tmp.at(rgb_data_offset + 2) == (uint8_t)0xff) {
//            continue;
//        }

        //new
        PortPar* port_par = new PortPar();
        port_par->addr = new QByteArray(tmp.data() + rgb_data_offset, 256 * 3);
        if ((*par_vec[sub_dev_id - 1])[port_id - 1] != NULL) {
            (*par_vec[sub_dev_id - 1])[port_id - 1 + 4] = port_par;
        } else {
            (*par_vec[sub_dev_id - 1])[port_id - 1] = port_par;
        }
    }
    ret = 0;
EXIT:
    if (ret == -1 && !par_vec.empty()) {
        if (image) {
            delete image;
            image = NULL;
        }
        clearParFile();
        throw RX203_ERR_CODE_PAR_FILE_ERR;
    }

    return ret;
}

void RX203_PTCL_Parsor::clearParFile()
{
    foreach (QVector<PortPar*>* tmp, par_vec) {
        foreach (PortPar* node, *tmp) {
            if (node) {
                if (node->addr)
                    delete node->addr;
                delete node;
            }
        }
        delete tmp;
    }
}

void RX203_PTCL_Parsor::taskListInit()
{
    task_list.clear();
}

void RX203_PTCL_Parsor::taskListDeinit()
{
    foreach (FrameOfPkt* tmp, task_list) {
        //tmp->mutex.lock();
        foreach (QByteArray* t, *(tmp->input_pkt_display_list)) {
            delete t;
        }
        tmp->input_pkt_display_list->clear();
        delete tmp->input_pkt_display_list;
        //tmp->mutex.unlock();
        delete tmp;
    }
    task_list.clear();
}

void RX203_PTCL_Parsor::portFlagInit()
{
    port_flag_vec.resize(par_vec.size());
    for (int i = 0; i < port_flag_vec.size(); i++) {
        port_flag_vec[i] = new PortFlag();
    }
}

void RX203_PTCL_Parsor::portFlagclear()
{
    port_flag_vec_mutex.lock();
    foreach (PortFlag* tmp, port_flag_vec) {
        tmp->port_x_get[0] = false;
        tmp->port_x_get[1] = false;
        tmp->port_x_get[2] = false;
        tmp->port_x_get[3] = false;
    }
    port_flag_vec_mutex.unlock();

}

void RX203_PTCL_Parsor::portFlagDeinit()
{
    foreach (PortFlag* tmp, port_flag_vec) {
        delete tmp;
    }
}

void RX203_PTCL_Parsor::threadSetInit()
{
    qDebug("will creat %d workers", workers_num);
    workerNodes_vec.resize(workers_num);
    for (int i = 0; i < workerNodes_vec.size(); i++) {
        workerNodes_vec[i] = new WorkerNode();
        workerNodes_vec[i]->worker = new ParseWorker(image, &par_vec);
        workerNodes_vec[i]->thread = new QThread();
        connect(workerNodes_vec[i]->thread, SIGNAL(started()),
                workerNodes_vec[i]->worker, SLOT(parseThread()));

        workerNodes_vec[i]->worker->moveToThread(workerNodes_vec[i]->thread);

        //connect 如果1. 没有线程在忙。2.队列为空。3.收到过同步帧 即发送
        connect(workerNodes_vec[i]->worker, SIGNAL(signal_frameComplete()),
                this, SLOT(slot_getFrameCompelet()));

    }
}

void RX203_PTCL_Parsor::threadSetDeinit()
{
    foreach (WorkerNode* t, workerNodes_vec) {
        t->worker->taskStop();
        t->thread->quit();
        t->thread->wait();
        delete t->worker;
        delete t->thread;
        delete t;
    }
    workerNodes_vec.clear();
}


